K8s 应用发布方案
项目背景
假设目标场景为需要发布名称为 DataAPI 的应用,此应用在 k8s 集群上共有 5 个 Pod,均为无状态的应用,分布在 2 个节点上。假设目前生产使用版本为 v1,待发布版本为 v2。
准备镜像
已推送镜像 ali-hb-test.huifutest.com/app/dataapi-canary 的 v1, v2 版本到指定测试镜像仓库。
基于 Deployment 创建 Pod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| apiVersion: apps/v1 kind: Deployment metadata: name: dataapi-canary-deploy namespace: default spec: replicas: 5 selector: matchLabels: app: dataapi release: canary template: metadata: labels: app: dataapi release: canary spec: containers: - name: dataapi-canary image: ali-art.huifutest.com/dev-v/app/dataapi-canary:v1 ports: - name: http containerPort: 80
|
1
| k apply -f dataapi-canary.yaml
|
1 2 3 4 5 6 7 8 9 10 11
| k get pods NAME READY STATUS RESTARTS AGE dataapi-canary-deploy-566b698f7f-csm8l 1/1 Running 0 58s dataapi-canary-deploy-566b698f7f-kcfbf 1/1 Running 0 48s dataapi-canary-deploy-566b698f7f-mkvv5 1/1 Running 0 50s dataapi-canary-deploy-566b698f7f-qrbsf 1/1 Running 0 1m dataapi-canary-deploy-566b698f7f-x8dgh 1/1 Running 0 57s dataapi-deployment-7f9bf79875-cftpx 1/1 Running 0 5d hmas-server-deployment-74bffc5f8c-q9dcm 1/1 Running 0 8d mind3-base-658944fcff-d544g 1/1 Running 14 4d vango-deployment-56484d676d-xrr9p 1/1 Running 0 4d
|
创建 Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| apiVersion: v1 kind: Service metadata: name: dataapi-canary-service namespace: default spec: selector: app: dataapi release: canary type: NodePort ports: - port: 80 targetPort: 80 nodePort: 30800
|
1
| k apply -f dataapi-canary-service.yaml
|
1 2 3
| k get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE dataapi-canary-service NodePort 172.16.1.57 <none> 80:30800/TCP 2m
|
访问测试
1 2
| curl http://192.168.25.38:30800 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
|
可以看到访问返回的内容为 V1
1
| while true ;do sleep 2; curl http://192.168.25.38:30800/hostname.html; done;
|
每隔两秒请求一次接口,可以看到 svc 是带有负载均衡效果的,平均分配到不同的 pod 上
金丝雀发布
核心思想
为什么叫金丝雀发布(Canary)?以前,旷工开矿,在下矿洞前需要检查下方是否有毒气,矿工们先会放一只金丝雀进去探是否有有毒气体,看金丝雀能否活下来。
金丝雀发布平是一种平滑过渡的一种发布方式 。产品上线,一方面要保证质量,另一方面保证刚上线的系统没有问题,这时候就需要设计一套灰度发布系统,让一部分用户继续使用产品A,另一部用户使用产品B,一旦出现问题可以很快的控制影响,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户流量都迁移到B上。
基于 replicas 实现
新建一个 deploy 配置文件,命名为 dataapi-canary-replicas.yaml。内容主要修改镜像版本为 v2,修改 replicas 为1,修改 deploy 名称为 dataapi-canary-deploy-v2,且 Pod 新增一个标签 version: v2.0 。详细信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| apiVersion: apps/v1 kind: Deployment metadata: name: dataapi-canary-deploy-v2 namespace: default spec: replicas: 1 selector: matchLabels: app: dataapi release: canary template: metadata: labels: app: dataapi release: canary version: v2.0 spec: containers: - name: dataapi-canary image: ali-art.huifutest.com/dev-v/app/dataapi-canary:v2 ports: - name: http containerPort: 80
|
新建 Pod 之后会看见一个新创建的 Pod
新建出来的 Pod 因为 包含标签 app: dataapi,release: canary 所以也能被 Service 标签选择器选中,并且我们设置数量为1(相当于放出一只金丝雀),我们进行访问测试,可以看到能访问到 v2 的接口。这里我们还能动态的设置新建的 deploy 的 replicas 数量,来实现测试不同的访问流量占比。
在真正的生产环境中我们现在就应该观察新发布的 v2 版本接口是否正常,如果正常那我们可以将 replicas 数量设置为之前 DataAPI 期待的 5个,并将之前的 deploy 删除,以此来实现平滑的过度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| apiVersion: apps/v1 kind: Deployment metadata: name: dataapi-canary-deploy-v2 namespace: default spec: replicas: 5 selector: matchLabels: app: dataapi release: canary template: metadata: labels: app: dataapi release: canary version: v2 spec: containers: - name: dataapi-canary image: ali-art.huifutest.com/dev-v/app/dataapi-canary:v2 ports: - name: http containerPort: 80
|
删除之前的 deploy
进行访问测试 就可以发现全部访问結果都为 v2 了,以此来实现平滑过渡,达到金丝雀发布的目的。
基于 strategy 实现
【注意】测试 rollout pause 之前,已将 Pod 镜像回滚至 v1 状态。
在 deployment 控制器中 spec 下有一个 strategy 字段能让我们灵活的配置 Pod 更新策略,查看描述信息如下:
type 为部署类型。可以是 “重新创建” 或 “滚动更新”。默认为滚动更新。当 type 为 “RollingUpdate” 时,我们可以配置 RollingUpdate 字段。RollingUpdate 字段详细信息如下:
其中 maxSurge 代表更新过程中新建 Pod 最大数量或者比例, maxUnavailable 为更新过程中删除 Pod 的数量或者比例。我们可以动态的调节这两个参数来实现 “金丝雀发布” 或者 “蓝绿部署”。
举例:目前 DataAPI Pod 部署数量为 5,假如我们设置 maxSurge 为 1,maxUnavailable 为 0,即表示在更新过程中只能最大新增一个 Pod,而能删减的 Pod 数量为 0,这时 DataAPI 存活的 Pod 数量为 6 个。由于我们设置的 replicas 为 5,也就是说我们期待的理想状态 Pod 数量是为 5个,但是现在为 6 个,肯定不符合需求!所以 deploy 控制器就会删除一个原来的 Pod。那有什么方法是在不影响以前的 Pod 上新增这一个 “金丝雀” 呢?这时我们就可以使用 pause 了。
pause 的作用是将发布进行暂停,此时将不受控制器控制。描述信息如下:
基于以上核心思想,我们就可以发布 v2 版本的 DataAPI 程序了。并且通过配置 strategy 信息和 pause 实现金丝雀发布,deploy 配置文件(这里主要新增 strategy 字段信息)如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| apiVersion: apps/v1 kind: Deployment metadata: name: dataapi-canary-deploy namespace: default spec: replicas: 5 selector: matchLabels: app: dataapi release: canary template: metadata: labels: app: dataapi release: canary spec: containers: - name: dataapi-canary image: ali-art.huifutest.com/dev-v/app/dataapi-canary:v1 ports: - name: http containerPort: 80 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0
|
执行 apply 更新 strategy信息:
1
| k apply -f dataapi-canary.yaml
|
查看 deploy 详细信息
1
| k describe deploy dataapi-canary-deploy
|
修改 deploy 文件,将 DataAPI 发布镜像版本改为 v2。并更新 Pod,让更新暂停
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| apiVersion: apps/v1 kind: Deployment metadata: name: dataapi-canary-deploy namespace: default spec: replicas: 5 selector: matchLabels: app: dataapi release: canary template: metadata: labels: app: dataapi release: canary spec: containers: - name: dataapi-canary image: ali-art.huifutest.com/dev-v/app/dataapi-canary:v2 ports: - name: http containerPort: 80 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0
|
1
| kubectl apply -f dataapi-canary.yaml && kubectl rollout pause deploy dataapi-canary-deploy
|
查看 Pod 可以看到新建了一个 Pod(相当于放出的金丝雀)
我们进行访问测试
1
| while true ; do curl http://192.168.25.38:30800; done;
|
可以看到访问的测试中,已经有了 v2 版本的请求响应。这时在真正的生产发布中我们就可以对 v2 版本的接口进行测试了,如果没有问题就可以继续发布下去了。将其余 v1 版本的接口完全替换为 v2 版本的接口。
1
| kubectl rollout resume deploy dataapi-canary-deploy
|
再次进行测试,就会发现服务已经更新为了 v2 版本。也就完成了一个完整的金丝雀发布。
总结
第一种方式较为简单,第二种方式比较难懂且较为复杂。合理的利用标签选择器和 strategy 还能实现蓝绿部署,A/B 测试等策略。